#pragma once

#include <iostream>
#include <vector>
#include "Sem.hpp"
#include "Mutex.hpp"

static const int gcap = 5; // for debug

using namespace SemModule;
using namespace MutexModule;

template<typename T>
class RingQueue
{
    public:
        RingQueue(int cap=gcap)
            :_cap(cap),
             _rq(cap),
             _blank_sem(cap),
             _p_step(),
             _data_sem(0),
             _c_step(0)
             {}
        void Equeue(const T&in)
        {
            //1.先申请信号量，因为信号量本质是资源的预定机制，预定好再谈访问临界资源指锁
            _blank_sem.P();
            {
                LockGuard lockguard(_pmutex);//RAII风格的锁
                //生产
                _rq[_p_step]=in;
                ++_p_step;
                _p_step%=_cap;
            }
            _data_sem.V();//
        }

        void Pop(T *out)
        {
            // 消费者
            // 1. 申请信号量，数据信号量
            _data_sem.P();
            {
                LockGuard lockguard(_cmutex);
                // 2. 消费
                *out = _rq[_c_step];
                // 3. 更新下标
                ++_c_step;
                // 4. 维持环形特性
                _c_step %= _cap;
            }
            _blank_sem.V();
        }

    private:
        std::vector<T> _rq;
        int _cap;
        // 生产者
        Sem _blank_sem; // 标识空位置数量
        int _p_step;    // 维护下标
        // 消费者
        //  消费者
        Sem _data_sem; // 数据
        int _c_step;
        // 维护生产和生产之间的互斥，消费和消费者的互斥
        Mutex _cmutex;
        Mutex _pmutex;
};